/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Global Trust Authority is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

use std::future::Future;
use std::pin::Pin;

use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
use common_log::{error, info};
use config_manager::types::context::CONFIG;
use nonce::nonce_interface::{validate_nonce, Nonce, ValidateNonceParams};

use crate::{
    chain::attestation_chain::{AttestationHandler, AttestationContext},
    entities::attest_request::Measurement,
    error::attestation_error::AttestationError,
};

/// Nonce validation processor
pub struct NonceValidationHandler {
    next: Option<Box<dyn AttestationHandler>>,
}

impl NonceValidationHandler {
    pub fn new() -> Self {
        Self { next: None }
    }

    /// Validate nonce request
    async fn validate_nonce_request(&self, measurement: &Measurement) -> Result<(), AttestationError> {
        let nonce_type = measurement.nonce_type.as_ref().map_or("verifier", |s| s);
        info!("Starting nonce validation with type: {}", nonce_type);
        match nonce_type {
            "user" => {
                if measurement.nonce.is_none() {
                    error!("Nonce parameter required but not provided");
                    return Err(AttestationError::NonceVerificationError("nonce parameter required".into()));
                }
                return Ok(());
            },
            "ignore" => return Ok(()),
            _ => {},
        }

        let nonce = measurement.nonce.as_ref().ok_or_else(|| {
            error!("Missing nonce in measurements");
            AttestationError::NonceVerificationError("missing nonce in measurements".into())
        })?;
        
        // Decode the base64 nonce string first
        let decoded_nonce = BASE64.decode(nonce).map_err(|e| {
            error!("Failed to decode base64 nonce: {}", e);
            AttestationError::NonceVerificationError(format!("failed to decode base64 nonce: {}", e))
        })?;
        
        // Convert the decoded bytes to a string
        let nonce_str = String::from_utf8(decoded_nonce).map_err(|e| {
            error!("Failed to convert nonce to string: {}", e);
            AttestationError::NonceVerificationError(format!("invalid nonce format: {}", e))
        })?;
        
        // Parse the JSON string into a Nonce struct
        let parsed_nonce: Nonce = serde_json::from_str(&nonce_str).map_err(|e| {
            error!("Failed to deserialize nonce: {}", e);
            AttestationError::NonceVerificationError(format!("invalid nonce format: {}", e))
        })?;

        info!("Validating nonce with period: {}", CONFIG.get_instance()?.attestation_service.nonce.nonce_valid_period);
        let validation_result = validate_nonce(ValidateNonceParams {
            valid_period: CONFIG.get_instance()?.attestation_service.nonce.nonce_valid_period,
            nonce: parsed_nonce,
        })
        .await;

        if !validation_result.is_valid {
            error!("Nonce validation failed: {}", validation_result.message);
            return Err(AttestationError::NonceVerificationError(validation_result.message));
        }

        Ok(())
    }
}

impl AttestationHandler for NonceValidationHandler {
    fn handle<'a>(&'a self, context: &'a mut AttestationContext) -> Pin<Box<dyn Future<Output = Result<(), AttestationError>> + Send + 'a>> {
        Box::pin(async move {
            // Validate nonce request using internal method
            self.validate_nonce_request(&context.measurement).await?;
            Ok(())
        })
    }
    
    fn set_next(&mut self, next: Box<dyn AttestationHandler>) {
        self.next = Some(next);
    }
    
    fn get_next(&self) -> Option<&dyn AttestationHandler> {
        self.next.as_ref().map(|h| h.as_ref())
    }
    
    fn name(&self) -> &'static str {
        "NonceValidation"
    }
}